
@using System.Web.WebPages.Scope;

@functions {
    
	private const string GetFormUrl = @"https://{0}.wufoo.com/api/v3/forms/{1}.json";

	private const string InitializedExceptionMessage = "The Wufoo Helper has not been initialized.";
	private const string ArgumentNullExceptionMessage = "Argument cannot be null or empty.";

	private static readonly object _subdomainKey = new object();
	private static readonly object _apiKey = new object();
    private static readonly object _handshakeKey = new object();
	private static readonly object _initializedKey = new object();
	
	public static string Subdomain {
		get {
			if (!Initialized) {
				throw new InvalidOperationException(InitializedExceptionMessage);
			}

			return (string)(ScopeStorage.CurrentScope[_subdomainKey] ?? "");
		}

		private set {
			if (value == null) {
				throw new ArgumentNullException("Subdomain");
			}

			ScopeStorage.CurrentScope[_subdomainKey] = value;
		}
	}

	public static string ApiKey {
		get {
			if (!Initialized) {
				throw new InvalidOperationException(InitializedExceptionMessage);
			}
			return (string)(ScopeStorage.CurrentScope[_apiKey] ?? "");
		}

		private set {
			if (value == null) {
				throw new ArgumentNullException("ApiKey");
			}

			ScopeStorage.CurrentScope[_apiKey] = value;
		}
	}
    
    public static Dictionary<string,List<string>> HandshakeKey {
		get {
			if (!Initialized) {
				throw new InvalidOperationException(InitializedExceptionMessage);
			}
			return (Dictionary<string,List<string>>)(ScopeStorage.CurrentScope[_handshakeKey] );
		}

		private set {
			if (value == null) {
				throw new ArgumentNullException("HandshakeKey");
			}

			ScopeStorage.CurrentScope[_handshakeKey] = value;
		}
	}    

	private static bool Initialized {
		get {
			return (bool)(ScopeStorage.CurrentScope[_initializedKey] ?? false);
		}
		
        set {
			ScopeStorage.CurrentScope[_initializedKey] = value;
		}
	}

	public static void Initialize(string apiKey, string subdomain) {		
        if (apiKey.IsEmpty()) {
            throw new ArgumentException(ArgumentNullExceptionMessage, "apiKey");
        }

        if (subdomain.IsEmpty()) {
            throw new ArgumentException(ArgumentNullExceptionMessage, "subdomain");
        }
      
		Subdomain = subdomain;
		ApiKey = apiKey;
        HandshakeKey= new Dictionary<string, List<string>>();
		Initialized = true;
	}
    
    /// <summary>
    /// Adds a handshake key to the dictionary, indexed by form hash
    /// </summary>
    /// <param name="hash">Wufoo form hash</param>
    /// <param name="key">Wufoo Webhook form handshake key</param>    
    public static void AddHandshakeKey(string hash, string key){        
        if( !HandshakeKey.ContainsKey(hash)){
            HandshakeKey[hash] = new List<string>();            
		}
        HandshakeKey[hash].Add(key);
	}
    
    /// <summary>
    /// Checks if the given key exist in the handshake keys collection for the given form hash, and returns true if the key is found
    /// </summary>
    /// <param name="hash">Wufoo form hash</param>
    /// <param name="key">Wufoo Webhook hash key</param>
    /// <returns></returns>
    public static bool ExistsHandshakeKey(string hash, string key){
        if (HandshakeKey.ContainsKey(hash)){
            if( HandshakeKey[hash].Contains(key)){    
                return true;
            }
		}        
        return false;
	}
    
    public class WebHookData{
        public Dictionary<string,dynamic> Fields{
            get;set;
		}
        
        public dynamic FormStructure {
            get;set;
		}
        
        public string HandshakeKey{
            get;set;
		}
        
        public string Ip{
            get;set;
		}
        
        public string CreatedBy{
            get;set;
		}
        
        public string DateCreated{
            get;set;
		}
        
        public string EntryId{
            get;set;
		}       
	}

    /// <summary>
    /// Stores the data from a webhook into the WebHookData structure, supporting wufoo fields.
    /// </summary>
    /// <param name="handshakeValidation">If set to True, the helper performs the validation of the handshake key sent in the POST request agains the initialized keys</param>
    /// <returns>A webhook object with data from the POST</returns>
    public static WebHookData GetWebHookData(bool handshakeValidation = false){
       
        if(HttpContext.Current.Request.Form == null) {
            throw new InvalidOperationException("The form is empty");
        }
        WebHookData webHookData = new WebHookData();
        webHookData.Fields = new Dictionary<string, dynamic>();
        webHookData.CreatedBy = HttpContext.Current.Request.Form["CreatedBy"];
        
        webHookData.DateCreated = HttpContext.Current.Request.Form["DateCreated"];
        webHookData.EntryId = HttpContext.Current.Request.Form["EntryId"];        
        webHookData.HandshakeKey = HttpContext.Current.Request.Form["HandShakeKey"];
        webHookData.Ip = HttpContext.Current.Request.Form["Ip"];
                
        webHookData.FormStructure = Json.Decode(HttpContext.Current.Request.Form["FormStructure"]);
                
        dynamic fieldStructure = Json.Decode(HttpContext.Current.Request.Form["FieldStructure"]);
        
        if(fieldStructure == null) {
            throw new InvalidOperationException("Field structure is not present. Check if the metadata checkbox is selected in Wufoo configuration");
        }
        
        if(handshakeValidation) {
            string formHash = webHookData.FormStructure.Hash.ToString();
            if(!ExistsHandshakeKey( formHash, webHookData.HandshakeKey )){
                 throw new InvalidOperationException("The handshake key initialized for this form is not matching the sender's form key");
			}      
        }
                
        foreach (dynamic field in fieldStructure.Fields){
            string type = field.Type.ToString();
            
            switch (type) { 
                case "text": 
                case "textarea": 
                case "number":                
                case "email": 
                case "phone": 
                case "url":
                case "money":
                case "date":
                case "time":                
                    field.Value = HttpContext.Current.Request.Form[field.ID];            
                    webHookData.Fields.Add(field.ID,field); 
                    break;
                    
                case "radio":
                case "select":
                    field.Value = HttpContext.Current.Request.Form[field.ID];                    
                    webHookData.Fields.Add(field.ID, field); 
                    break;
                    
                case "checkbox":
                    var selectedList = new List<dynamic>();                    
                    
                    var value = "";
                    foreach (dynamic element in field.SubFields) {
                        string label = HttpContext.Current.Request.Form[element.ID];
                        if (!label.IsEmpty()) {
                            selectedList.Add(label);
                            value += (value.IsEmpty() ? "" : ", ") + label ;
                        }                        
                    }
                    
                    value.TrimEnd(new char[] {','});
                    field.Value = value;
                    
                    field.SelectedValues = selectedList;                                        
                    webHookData.Fields.Add(field.ID, field);
                    break;
                    
                case "file":                     
                    field.AttachName = field.Value;
                    field.AttachURL = HttpContext.Current.Request.Form[field.ID + "-url"];

                    field.Value = HttpContext.Current.Request.Form[field.ID];
                    webHookData.Fields.Add(field.ID, field);
                    break;

                case "shortname":                    
                    field.Name = HttpContext.Current.Request.Form[field.SubFields[0].ID];
                    field.LastName = HttpContext.Current.Request.Form[field.SubFields[1].ID];
                    
                    field.Value = field.Name + " " + field.LastName;                    
                    webHookData.Fields.Add(field.ID, field);
                    break;
                    
                case "address":
                    field.Street = HttpContext.Current.Request.Form[field.SubFields[0].ID];
                    field.Address = HttpContext.Current.Request.Form[field.SubFields[1].ID];
                    field.City = HttpContext.Current.Request.Form[field.SubFields[2].ID];
                    field.State = HttpContext.Current.Request.Form[field.SubFields[3].ID];
                    field.Zip = HttpContext.Current.Request.Form[field.SubFields[4].ID];
                    field.Country = HttpContext.Current.Request.Form[field.SubFields[5].ID];
                    
                    field.Value = field.Street + 
                                 (!string.IsNullOrEmpty(field.Address) ? ", " + field.Address : "") + 
                                 (!string.IsNullOrEmpty(field.Zip) ? ", " + field.Zip : "") + 
                                 (!string.IsNullOrEmpty(field.City) ? ", " + field.City : "") +
                                 (!string.IsNullOrEmpty(field.State) ? ", " + field.State : "") +
                                 (!string.IsNullOrEmpty(field.Country) ? ", " + field.Country : "");
                    
                    webHookData.Fields.Add(field.ID, field);      
                    break;
                    
                case "likert":                                      
                    for (int i = 0; i < field.SubFields.Length; i++) { 
                        field.SubFields[i].Value = HttpContext.Current.Request.Form[field.SubFields[i].ID] ?? "";
                       // field.Value += field.SubFields[i].Label + ":" +" " + field.SubFields[i].Value + "| ";
                    }
                    webHookData.Fields.Add(field.ID, field);  
                    break;
            }
        }
        return webHookData;
	}
    
	@*
	Summary:
		Retrieves details about the specified form.

	Parameter: formIdentifier
		The form identifier, weather in its Friendly URL form ('my-sample-form') and a Hashed URL form ('w7x1p5');
	*@
    public static dynamic GetForm(string formIdentifier) {
		var client = new WebClient();
        client.Credentials = new NetworkCredential(ApiKey, "password");

        var receiveStream = client.OpenRead(string.Format(GetFormUrl, Subdomain, formIdentifier));
        var result = new StreamReader(receiveStream).ReadToEnd();
        var forms = Json.Decode(result);

        return forms["Forms"][0];
    }
}

@*
Summary:
    Shows an embedded Wufoo form on your page. Once on your site, everything related to the form will work: validation will occur,
    confirmation emails will be sent, and the data will be sent to your Wufoo account.

Parameter: formHash
    The form's hash identifier.
Parameter: version
    The rendered version of the form: "javascript" (default) or "iframe".
Parameter: height
    The height of the form in pixels. The height parameter can be changed so that it fits into your site accordingly. 
    Keep in mind that when someone submits your form with errors, the form height will grow because the error messages need to be displayed.
    When you are considering a height for your form, leave enough room for the error messages.
Parameter: autoResize
    Automatically arranges the size of the embedded form in your page. This parameter only works for the "javascript" version. 
    If autoResize = true, the height parameter is ignored.
*@
@helper EmbedForm(string formHash,						
                  string version = "javascript",
                  int height = 500,
                  bool autoResize = true) {

    if (string.Equals(version, "javascript", StringComparison.InvariantCultureIgnoreCase)) {
        
        <script type="text/javascript">
            var host = (("https:" == document.location.protocol) ? "https://secure." : "http://");
            document.write(unescape("%3Cscript src='" + host + "wufoo.com/scripts/embed/form.js' type='text/javascript'%3E%3C/script%3E"));
        </script>        
        <script type="text/javascript">
            var @(formHash) = new WufooForm();
            @(formHash).initialize({'userName':'@Subdomain', 
                               'formHash':'@formHash', 
                               'autoResize':@autoResize.ToString().ToLowerInvariant(),
                               'height':@height});
            @(formHash).display();
        </script>
	} else {
        <iframe src="http://@(Subdomain).wufoo.com/embed/@formHash/" height="@height" allowTransparency="true" frameborder="0" scrolling="no" style="width:100%;border:none">
        </iframe>
	}
}
